//
// Created by 邹嘉旭 on 2025/8/5.
//
#include <ld_log.h>
#include "elements/amm.h"

#include "as_entity.h"
#include "define.h"

static l_err init_amm_as_entities(net_element_t *net_ele) {
    for (int i = 0; i < 40; i++) {
        as_entity_t *as = init_as_entity(1012345 + i * 10000, 301 + i, 16, ELEMENT_AMM, net_ele);

        set_as_enode(net_ele->as_map, as);
    }

    return LD_OK;
}

amm_entity_t *init_amm_entity() {
    amm_entity_t *amm_entity = malloc(sizeof(amm_entity_t));

    amm_entity->sac_bitset = init_bitset( MAX_SAC, sizeof(uint8_t), NULL, NULL);

    return amm_entity;
}

void free_amm_entity(amm_entity_t *entity) {
    free(entity);
}

static l_err amm_server_handler(basic_conn_t *bc) {
    if (!bc || !bc->read_pkt ) {
        log_error("AMM recv failed");
        return LD_ERR_INTERNAL;
    }
    element_propt_t *element_propt = (element_propt_t *) bc;

    net_ctx_t *ctx = bc->opt;
    meta_service_t *meta = ctx->arg;

    // cn_log_buf(LOG_INFO, meta->net_ele->element_tag, meta->interface_type, "RECV AMM", element_propt->bc.read_pkt->ptr,
    //            element_propt->bc.read_pkt->len);

    size_t format_size = 0;
    cn_format_desc_t *formats = NULL;


    switch (meta->interface_type) {
        case INTERFACE_G1:
            formats = g1_format_descs;
            format_size = g1_format_size;
            break;
        case INTERFACE_G5:
            formats = g5_format_descs;
            format_size = g5_format_size;
            break;
        default:
            cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Invalid Interface Type");
            return LD_ERR_INVALID;
    }

    if (format_size == 0 || formats == NULL) {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Formant Error");
        return LD_ERR_INVALID;
    }

    uint8_t type = *element_propt->bc.read_pkt->ptr;
    cn_format_desc_t *recv_desc = get_non_sequential_desc(format_size, formats, type);
    if (!recv_desc) {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No desc");
        return LD_ERR_NULL;
    }

    if (recv_desc->recv_handler) {
        if (recv_desc->recv_handler(meta->net_ele, recv_desc, element_propt->bc.read_pkt, element_propt) != LD_OK) {
            cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Handle Message Failed!");
            return LD_ERR_INVALID;
        }
    }else {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No handler");
            return LD_ERR_INVALID;
    }

    return LD_OK;
}

/**
 * AMM 客户端业务（G3接口）
 * @param bc
 * @return
 */
static l_err amm_client_handler(basic_conn_t *bc) {
    if (!bc || !bc->read_pkt ) {
        log_error("AMM client recv failed");
        return LD_ERR_NULL;
    }
    element_propt_t *element_propt = (element_propt_t *) bc;

    net_ctx_t *ctx = bc->opt;
    meta_service_t *meta = ctx->arg;

    // cn_log_buf(LOG_INFO, meta->net_ele->element_tag, meta->interface_type, "RECV AMM", element_propt->bc.read_pkt->ptr,
    //            element_propt->bc.read_pkt->len);
    uint8_t type = *element_propt->bc.read_pkt->ptr ;

    cn_format_desc_t *recv_desc = get_non_sequential_desc(g3_format_size, g3_format_descs, type);
    if (!recv_desc) {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No desc");
        return LD_ERR_NULL;
    }

    if (recv_desc->recv_handler) {
        if (recv_desc->recv_handler(meta->net_ele, recv_desc, element_propt->bc.read_pkt, element_propt) != LD_OK) {
            cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Handle Message Failed!");
            return LD_ERR_INVALID;
        }
    }else {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No handler");
        return LD_ERR_INVALID;
    }

    return LD_OK;
}

void *exec_amm(void *args) {
    net_element_t *net_ele = args;
    if (!net_ele)   return NULL;
    net_ele->inline_element = init_amm_entity();
    if (init_element_service(net_ele, amm_server_handler, amm_client_handler) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED,"Init element failed");
        return NULL;
    }

    if (direct_snp) {

        while (1) {
            uint8_t connected_peer = 0;
            FOREACH_PEERS(net_ele->server_interfaces, {
                if (peer->is_connect == TRUE) {
                    connected_peer++;
                }
                });

            if (connected_peer == net_ele->server_interface_count) break;
            usleep(10000);
        }

        if (init_amm_as_entities(net_ele) != LD_OK) {
            log_error("Cannot init 40 air stations");
            return NULL;
        }
    }

    cn_log_info(net_ele->element_tag, INTERFACE_UNDEFINED, "exec finished");

    return NULL;
}

l_err start_amm(net_element_t *net_ele) {
    cn_log_info(net_ele->element_tag, INTERFACE_UNDEFINED, "start");
    pthread_create(&net_ele->th, NULL, exec_amm, net_ele);
    pthread_detach(net_ele->th);
    return LD_OK;
}

l_err stop_amm(net_element_t *net_ele) {
    cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "stop");
    if (net_ele->inline_element) {
        free_amm_entity(net_ele->inline_element);
    }
    return LD_OK;
}
